﻿using System;
using System.IO;
using System.Web;
using System.Web.Mvc;

using WebMarkupMin.AspNet.Common;
using WebMarkupMin.AspNet4.Common;

namespace WebMarkupMin.AspNet4.Mvc
{
	/// <summary>
	/// Represents an attribute, that applies HTTP compression to the action result
	/// </summary>
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public sealed class CompressContentAttribute : ActionFilterAttribute
	{
		/// <summary>
		/// WebMarkupMin configuration
		/// </summary>
		private readonly WebMarkupMinConfiguration _configuration;

		/// <summary>
		/// HTTP compression manager
		/// </summary>
		private readonly IHttpCompressionManager _compressionManager;


		/// <summary>
		/// Constructs a instance of HTTP compressesion attribute
		/// </summary>
		public CompressContentAttribute()
		{
			_configuration = WebMarkupMinConfiguration.Instance;
			_compressionManager = null;
		}


		/// <summary>
		/// Override to compress the content that is generated by an action method
		/// </summary>
		/// <param name="filterContext">Filter context</param>
		public override void OnActionExecuting(ActionExecutingContext filterContext)
		{
			if (!_configuration.IsCompressionEnabled())
			{
				return;
			}

			IHttpCompressionManager compressionManager =
				_compressionManager ?? HttpCompressionManager.Current;
			HttpContextBase context = filterContext.HttpContext;
			HttpRequestBase request = context.Request;
			HttpResponseBase response = context.Response;
			string httpMethod = request.HttpMethod;
			string currentUrl = request.RawUrl;

			if (response.Filter != null
				&& compressionManager.IsSupportedHttpStatusCode(response.StatusCode)
				&& compressionManager.IsSupportedHttpMethod(httpMethod)
				&& compressionManager.IsProcessablePage(currentUrl))
			{
				context.Items["originalResponseFilter"] = response.Filter;

				string acceptEncoding = request.Headers["Accept-Encoding"];
				response.Filter = new HttpCompressionFilterStream(response, compressionManager, acceptEncoding);
			}
		}

		/// <summary>
		/// Override to handle error
		/// </summary>
		/// <param name="filterContext">Filter context</param>
		public override void OnResultExecuted(ResultExecutedContext filterContext)
		{
			if (filterContext.Exception != null)
			{
				HttpContextBase context = filterContext.HttpContext;
				if (context.Items.Contains("originalResponseFilter"))
				{
					var originalResponseFilter = context.Items["originalResponseFilter"] as Stream;
					if (originalResponseFilter != null)
					{
						context.Response.Filter = originalResponseFilter;
					}
				}
			}
		}
	}
}